#import "balls.h"


@implementation balls
- (void)awakeFromNib
{
	if ([[self superclass] instancesRespondToSelector:@selector(awakeFromNib)])
		[super awakeFromNib];
	
	[NSApp setDelegate:self];
}



- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
	mRunning = NO;
	
	mWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
				styleMask:NSBorderlessWindowMask
				backing:NSBackingStoreBuffered
				defer:NO];
	
	[mWindow setCanHide:NO];
	[mWindow makeFirstResponder:self];
	[mWindow setAutodisplay:YES];
	[mWindow setContentView:self];
	[mWindow setDelegate:self];
	[mWindow setExcludedFromWindowsMenu:YES];
	[mWindow setHasShadow:NO];
	[mWindow useOptimizedDrawing:YES];
	
	[mWindow setBackgroundColor:[NSColor blackColor]];
	[mWindow setLevel:kCGDesktopWindowLevel];
	
	[mWindow orderBack:self];
	[self setTimerInterval:.05 source:NULL];
}



- (void)setTimerRunning:(BOOL)run source:(id)source
{
    if (!mRunning && run)
	{
		mTimer = [[NSTimer scheduledTimerWithTimeInterval:mInterval
                            target:self
                            selector:@selector(drawAnother:)
                            userInfo:NULL
                            repeats:YES
            	      ] retain];
        mRunning = YES;
    }
	else if (mRunning && !run)
	{
        // We're running and we've been told not to, so let's stop.
        [mTimer invalidate];
        [mTimer release];
        mTimer = NULL;
        mRunning = NO;
    }
}



- (void)setTimerInterval:(float)interval source:(id)source
{
    mInterval = interval;
	
    if (mRunning)
        [self setTimerRunning:NO source:source];
    
    [self setTimerRunning:YES source:source];
}



static float RandFloat(void)
{
    return ((float) rand() / (float) RAND_MAX);
}



- (void)drawRandomBallInside:(const NSRect *)rect
{
    float	x, y;
	float	minBallSize = 30.0;
	float	maxBallSize = 100.0;
	float	damp = .75;
    NSBezierPath *oval;

    // Calculate where the ball should go.
    
    x = rect->origin.x + rect->size.width * RandFloat();
    y = rect->origin.x + rect->size.height * RandFloat();

    // Set the current colour to a random RGB value.
    [[NSColor colorWithDeviceRed:(RandFloat() * damp)
							green:(RandFloat() * damp)
							blue:(RandFloat() * damp)
							alpha:(fabs(RandFloat()) * damp)] set];

    // Now construct a bezier path for an circle and draw it.
    oval = [NSBezierPath bezierPath];
    [oval appendBezierPathWithOvalInRect:NSMakeRect(x, y,
			minBallSize + (fabs(RandFloat()) * (maxBallSize - minBallSize)),
			minBallSize + (fabs(RandFloat()) * (maxBallSize - minBallSize)))];
    [oval fill];
}



- (void)drawRect:(NSRect)rect
{
    // Do nothing.  In a normal view, you would update the visual
    // representation of your view inside this method.  However, SillyBallView
    // does not remember which balls that it's drawn, so there is nothing it
    // can draw in this meathod.  Instead the drawing happens asynchronously
    // inside the drawAnother: method.  See the notes in ReadMe.rtf for details.
}



- (void)drawAnother:(id)timer
{
    NSRect visRect;

    // Lock focus on ourselves.  We need to do this because we're drawing
    // outside of the context of NSView's drawRect: method.  This is relatively
    // unusual behaviour for a view.  See the discussion of this in ReadMe.rtf.
    
    [self lockFocus];
	
    // Now draw a random ball inside the view.
    visRect = [self visibleRect];
    [self drawRandomBallInside:&visRect];
	
    // And unlock the focus.
    [self unlockFocus];
	
    [[self window] flushWindow];
}
@end
